其他
android so文件攻防实战-libDexHelper.so反混淆
本文为看雪论坛精华文章
看雪论坛作者ID:houjingyi
去除混淆
1.垃圾指令
这些垃圾指令是在switch的一个永远不会被执行到的分支里面,可以直接将IDA不能MakeCode的地方patch成NOP再MakeCode。
2.字符串加密
我最后用的是下面这种方案:以0x40110处调用0x186C4处的解密函数为例,这里面字符串解密的逻辑比较简单,需要三个参数。我们可以自己实现也可以用unicorn,我就用unicorn了。
import sys
import unicorn
import binascii
import threading
import subprocess
from capstone import *
from capstone.arm64 import *
with open("C:\\Users\\hjy\\Downloads\\out1.fix.so","rb") as f:
sodata = f.read()
uc = unicorn.Uc(unicorn.UC_ARCH_ARM64, unicorn.UC_MODE_ARM)
code_addr = 0x0
code_size = 8*0x1000*0x1000
uc.mem_map(code_addr, code_size)
stack_addr = code_addr + code_size
stack_size = 0x1000000
stack_top = stack_addr + stack_size - 0x8
uc.mem_map(stack_addr, stack_size)
uc.mem_write(code_addr, sodata)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X29, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X28, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X27, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X26, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X25, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X24, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X23, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X22, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X21, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X20, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X19, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X18, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X17, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X16, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X15, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X14, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X13, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X12, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X11, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X10, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X9, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X8, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X7, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X6, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X5, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X4, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X3, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X0, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_SP, stack_top)
X0 = uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
uc.mem_write(X0, bytes.fromhex(sys.argv[1]))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1, int(sys.argv[2], 16))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2, int(sys.argv[3], 16))
uc.emu_start(0x1777C, 0x17780)
X0 = uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
decstr = uc.mem_read(X0, 80)
print("decstr:", decstr)
uc.mem_unmap(stack_addr, stack_size)
uc.mem_unmap(code_addr, code_size)
import unicorn
import binascii
import threading
import subprocess
from capstone import *
from capstone.arm64 import *
inscnt = 0
start_addr = 0
end_addr = 0
stop_addr = 0
stop_addr_list = []
def hook_code(uc, address, size, user_data):
global inscnt
global end_addr
global stop_addr
global stop_addr_list
md = Cs(CS_ARCH_ARM64, CS_MODE_ARM)
for ins in md.disasm(sodata[address:address + size], address):
#rint(">>> 0x%x:\t%s\t%s" % (ins.address, ins.mnemonic, ins.op_str))
stop_addr = ins.address
if ins.address in stop_addr_list:
#print("will pass 0x%x:\t%s\t%s" %(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address + size)
return
inscnt = inscnt + 1
if (inscnt > 500):
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, 0xffffffff)
return
if ins.mnemonic.find("b.") != -1:
print("will pass 0x%x:\t%s\t%s" %(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address + size)
return
if ins.mnemonic.find("bl") != -1:
print("will pass 0x%x:\t%s\t%s" %(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address + size)
return
if ins.op_str in ["x0","x1","x2","x3"]:
X1 = uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X1)
if X1 > 0x105A88:
print("will pass 0x%x:\t%s\t%s" %(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address + size)
return
if ins.op_str.startswith("#0x"):
addr = int(ins.op_str[3:],16)
if (addr > 0x14E50 and addr < 0x15820) \
or addr == 0x186C4 \
or addr > 0x105A88:
print("will pass 0x%x:\t%s\t%s" %(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address + size)
return
def call_prepare_arg():
global inscnt
global start_addr
global end_addr
global stop_addr
global stop_addr_list
inscnt = 0
uc = unicorn.Uc(unicorn.UC_ARCH_ARM64, unicorn.UC_MODE_ARM)
code_addr = 0x0
code_size = 8*0x1000*0x1000
uc.mem_map(code_addr, code_size)
stack_addr = code_addr + code_size
stack_size = 0x1000000
stack_top = stack_addr + stack_size - 0x8
uc.mem_map(stack_addr, stack_size)
uc.hook_add(unicorn.UC_HOOK_CODE, hook_code)
uc.mem_write(code_addr, sodata)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X29, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X28, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X27, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X26, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X25, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X24, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X23, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X22, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X21, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X20, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X19, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X18, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X17, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X16, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X15, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X14, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X13, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X12, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X11, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X10, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X9, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X8, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X7, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X6, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X5, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X4, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X3, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X0, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_SP, stack_top)
uc.emu_start(start_addr, end_addr)
X0 = uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
decstr = uc.mem_read(X0, 80)
end_index = decstr.find(bytearray(b'\x00'), 1)
decstr = decstr[:end_index]
decstr = binascii.b2a_hex(decstr)
decstr = decstr.decode('utf-8')
X1 = uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X1)
X2 = uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X2)
pi = subprocess.Popen(['C:\\Python38\\python.exe', 'decstr.py', decstr, hex(X1), hex(X2)], stdout=subprocess.PIPE)
output = pi.stdout.read()
print(output)
def loop_call_prepare_arg1():
global inscnt
global end_addr
global stop_addr
global stop_addr_list
loopcnt = 0
stop_addr_list = []
while True:
try:
loopcnt = loopcnt + 1
if(loopcnt > 200):
break
call_prepare_arg()
except unicorn.unicorn.UcError:
print("adding....")
print(hex(stop_addr))
stop_addr_list.append(stop_addr)
else:
break
def loop_call_prepare_arg2():
global inscnt
global end_addr
global stop_addr
global stop_addr_list
global start_addr
loopcnt = 0
stop_addr_list = []
while True:
try:
loopcnt = loopcnt + 1
if(loopcnt > 200):
break
call_prepare_arg()
except unicorn.unicorn.UcError:
start_addr = stop_addr + 4
else:
break
with open("C:\\Users\\hjy\\Downloads\\out1.fix.so","rb") as f:
sodata = f.read()
all_addr = []
with open('xref_decstr.txt', 'r', encoding='utf-8') as f:
for line in f:
addr = "0x" + line[2:]
addr = int(addr, 16)
all_addr.append(addr)
for i in all_addr:
print("i:")
print(hex(i))
end_addr = i
CODE = sodata[i - 4:i]
md = Cs(CS_ARCH_ARM64, CS_MODE_ARM)
for x in md.disasm(CODE, i - 4):
mnemonic = x.mnemonic
while mnemonic != "ret" \
and mnemonic != "b" \
and mnemonic != "br" \
and mnemonic != "cbz" \
and mnemonic != "cbnz":
i = i - 4
CODE = sodata[i - 4:i]
for x in md.disasm(CODE, i - 4):
mnemonic = x.mnemonic
start_addr = i
print("start_addr:")
print(hex(start_addr))
print("end_addr:")
print(hex(end_addr))
loop_call_prepare_arg1()
loop_call_prepare_arg2()
3.控制流混淆
第二种是动态计算跳转地址,基本上类似于在android so文件攻防实战-某团libmtguard.so反混淆(https://bbs.pediy.com/thread-271853.htm)见过的那种,但是要更复杂。
比如这里的指令,在0x1DA0C处给X2赋值,X2此时为.data段中的一个地址,W0为偏移,取出值后在0x1DA18处乘4加上0x1DA20,最后的值就是0x1DA1C处X0的值。那么需要解决这么几个问题:
如何确定0x1DA0C处给X2赋的值;
找到所有会跳转到0x1DA1C的指令,将跳转地址改成计算出来的X0的值。
第一个问题,其实和字符串解密面临的情况是类似的,比如这里需要找到和"LDR X2, [X29,#0x190+var_118]"对应的"STR XX, [X29,#0x190+var_118]"这条指令,然后再找给XX寄存器赋值的指令,然而这两条指令很可能和BR X0隔了好几个block。我的解决方法是通过IDA提供的idaapi.FlowChar功能,递归前面的block查找。不足之处在于前提条件是IDA正确识别了函数的起始地址,否则会出现我们需要的指令和BR X0不在同一个函数的情况,这样就处理不了。
第二个问题,在递归前面的block的时候就先找到0x1D9D4处这条给W0赋值的指令,然后从0x1D9D4处开始直到0x1DA1C,找到第一个存在交叉引用的地址,也就是0x1DA04。它的前一条指令0x1DA00就是需要改成跳转指令的地方。
第三个问题,确定了0x1DA00之后,那么从0x1DA00到0x1DA1C所有存在交叉引用的地址都要去交叉引用的地方修改跳转地址。不过这里有很多细节。
(1)如果W0是由CSEL,CSET,CSINC这些指令赋值的,像下面这种情况,那么需要把0x1DE80和0x1DE84修改成 B.GE和B.LT。
patch前:
最后的脚本放附件了。当然还有一些脚本处理不了的地方,不过问题已经不算太大了,需要的话可以动态调试确定。
4.函数地址动态计算
这个在IDA里面是能看清楚的,v35其实就是off_12EB80[0],即调用0x80FE0处的p329AAB59961F6410ABA963EF972FE303。
接下来我们就来分析libDexHelper.so,来看看它都干了些什么。精力有限,很多地方没能很详细去分析。有些地方分析的可能也不一定对,将就看吧。
功能分析
0x15960
libDexHelper.so
libDexHelper-x86.so
libDexHelper-x86_64.so
/system/lib64/libart.so
/system/lib64/libLLVM.so
/system/framework/arm64/boot-framework.oat
/system/lib64/libskia.so
/system/lib64/libhwui.so
.oat
ff c3 01 d1 f3 03 04 aa f4 03 02 aa f5 03 01 aa e8 03 00 aa
GumInvocationListener
GSocketListenerEvent
0x16A30
ro.yunos.version
ro.yunos.version.release
persist.sys.dalvik.vm.lib
persist.sys.dalvik.vm.lib.2
/system/bin/dex2oat
LD_OPT_PACKAGENAME
LD_OPT_ENFORCE_V1
0x17A70
0x186C4
0x19674
0x19778
0x1987C
0x19998
0x19b48
0x19E08
0x1A058
/etc
/sbin
/system
/system/bin
/vendor/bin
/system/sbin
/system/xbin
0x1A740
com.yellowes.su
eu.chainfire.supersu
com.noshufou.android.su
com.thirdparty.superuser
com.koushikdutta.superuser
com.noshufou.android.su.elite
0x1AF1C
com.chelpus.lackypatch
com.ramdroid.appquarantine
com.koushikdutta.rommanager
com.dimonvideo.luckypatcher
com.ramdroid.appquarantinepro
com.koushikdutta.rommanager.license
0x1B7D0
com.saurik.substrate
com.formyhm.hideroot
com.amphoras.hidemyroot
com.devadvance.rootcloak
com.formyhm.hiderootPremium
com.devadvance.rootcloakplus
com.amphoras.hidemyrootadfree
com.zachspong.temprootremovejb
de.robv.android.xposed.installer
0x1C61C
0x1C8D8
/sbin/
/su/bin/
/data/local/
/system/bin/
/system/xbin/
/data/local/bin/
/system/sd/xbin/
/data/local/xbin/
/system/bin/.ext/
/system/bin/failsafe/
/system/usr/we-need-root/
0x1D518
.cache
oat
.payload
v1filter.jar
classes.odex
classes.vdex
classes.dex
assets/classes.jar
.cache/classes.jar
.cache/classes.dex
.cache/classes.odex
.cache/classes.vdex
0x1E520
0x137BB0 fopen
0x137BB8 fclose
0x137BC0 fgets
0x137BC8 fwrite
0x137BD0 fread
0x137BD8 sprintf
0x137BE0 pthread_create
0x1F250
0x1F710
0x1FDC8
RegisterNative(com/secneo/apkwrapper/H, attach(Landroid/app/Application;Landroid/content/Context;)V, RX@0x4002f6e4[libDexHelper.so]0x2f6e4)
RegisterNative(com/secneo/apkwrapper/H, b(Landroid/content/Context;Landroid/app/Application;)V, RX@0x400247c0[libDexHelper.so]0x247c0)
RegisterNative(com/secneo/apkwrapper/H, c()V, RX@0x40024c08[libDexHelper.so]0x24c08)
RegisterNative(com/secneo/apkwrapper/H, d(Ljava/lang/String;)Ljava/lang/String;, RX@0x40023d04[libDexHelper.so]0x23d04)
RegisterNative(com/secneo/apkwrapper/H, e(Ljava/lang/Object;Ljava/util/List;Ljava/lang/String;)[Ljava/lang/Object;, RX@0x40035ab0[libDexHelper.so]0x35ab0)
RegisterNative(com/secneo/apkwrapper/H, f()[Ljava/lang/String;, RX@0x4001a740[libDexHelper.so]0x1a740)
RegisterNative(com/secneo/apkwrapper/H, g()[Ljava/lang/String;, RX@0x4001af1c[libDexHelper.so]0x1af1c)
RegisterNative(com/secneo/apkwrapper/H, h()[Ljava/lang/String;, RX@0x4001b7d0[libDexHelper.so]0x1b7d0)
RegisterNative(com/secneo/apkwrapper/H, n()[Ljava/lang/String;, RX@0x4001c8d8[libDexHelper.so]0x1c8d8)
RegisterNative(com/secneo/apkwrapper/H, j()[Ljava/lang/String;, RX@0x4001a058[libDexHelper.so]0x1a058)
RegisterNative(com/secneo/apkwrapper/H, k()Ljava/lang/String;, RX@0x40019778[libDexHelper.so]0x19778)
RegisterNative(com/secneo/apkwrapper/H, l()Ljava/lang/String;, RX@0x4001987c[libDexHelper.so]0x1987c)
RegisterNative(com/secneo/apkwrapper/H, m()Ljava/lang/String;, RX@0x40019674[libDexHelper.so]0x19674)
RegisterNative(com/secneo/apkwrapper/H, bb(Landroid/content/Context;Landroid/app/Application;Landroid/app/Application;)V, RX@0x4002921c[libDexHelper.so]0x2921c)
RegisterNative(com/secneo/apkwrapper/H, o(Landroid/content/Context;)I, RX@0x4002f158[libDexHelper.so]0x2f158)
RegisterNative(com/secneo/apkwrapper/H, p()V, RX@0x4001875c[libDexHelper.so]0x1875c)
RegisterNative(com/secneo/apkwrapper/H, q()I, RX@0x40023568[libDexHelper.so]0x23568)
RegisterNative(com/secneo/apkwrapper/H, mu()I, RX@0x4001f250[libDexHelper.so]0x1f250)
0x218A8
0x22068
/data/usr/0/包名/.cache/oat
/data/usr/0/包名/.cache/oat/arm64
/data/usr/0/包名/.payload
0x22a90
vboxsf
/mnt/shared/install_apk
nemusf
/mnt/shell/emulated/0/Music sharefolder
/sdcard/windows/BstSharedFolder
0x23568
0x247C0
0x24C08
0x26278
0x27290
0x2921C
0x29CE8
com.bignox.app.store.hd
com.bluestacks.appguidance
com.bluestacks.settings
com.bluestacks.home
com.bluestack.BstCommandProcessor
com.bluestacks.appmart
0x2B670
0x2CAE0
0x2F158
/sbin/.magisk/
/sbin/.core/img
/sbin/.core/mirror
/sbin/.core/db-0/magisk.db
0x2F6E4
0x31474
查看/proc/self/maps:
anon:dalvik-classes.dex extracted in memory from v1filter.jar
anon:dalvik-DEX data
把多出来这样的段dump下来。
原始dex:
指令虚拟化是调用JniLib.cV解析执行的,最后一个参数是一个函数code索引,用来查找被虚拟化后的指令,其它是方法参数:
v1filter.jar:
0x3371C
0x339FC
0x34A00
0x351DC
0x35AB0
0x3766C
/data/user/0/cn.missfresh.application/.cache/classes.jar
/data/user/0/cn.missfresh.application/.cache/classes.dex
/data/user/0/cn.missfresh.application/.cache/v1filter.jar
(看别人的分析应该读assets下面两个文件:classes0.jar是被加密的dex,classes.dgc是被加密的抽取后的指令。不过我分析的这个样本中没有classes0.jar和classes.dgc,可能是名字变了)
0x398F8/0x3A08C
_Z16hprofDumpClassesP15hprof_context_t
_Z12dvmDumpClassPK11ClassObjecti
_Z9dumpClassP7DexFilei
dumpclass
dump_class
0x3BF10
0x3BF7C
ueventd.ttVM_x86.rc
init.ttVM_x86.rc
fstab.ttVM_x86
bluestacks
BlueStacks
0x3D814
0x42378
0x44708
vmDebug::notifyDebuggerActivityStart(hook后:0x446C0)
art::Dbg::GoActive(hook后:0x446E4)
art::Runtime::AttachAgent(hook后:0x45CF8)
0x46194
0x4C2F0
art::ClassLinker::DefineClass(hook后:0x46BB8)
art::ClassLinker::LoadMethod(hook后:0x46ED4/0x47BB8/0x488C0/0x491F8/0x49B0C)
art::OatFile::OatMethod::LinkMethod(hook后:0x46BD8/0x46DB0)
0x4DB80
0x50280
0x5074C
0x50B60
0x57424
0x598FC
0x59CE8
0x5C600
0x61E3C
fstatat64(hook后:0x5E778)
stat(hook后:0x5E858)
close(hook后:0x5EA20)
openat(hook后:0x5ED20)
open(hook后:0x5ED9C)
pread(hook后:0x5FAB8)
read(hook后:0x5FC14)
mmap64(hook后:0x5FDDC)
__openat_2(hook后:0x5FEF4)
__open_2(hook后:0x5FF74)
0x64AE8
0x65FE4
0x67544
art::DexFileLoader::open(hook后:0x6D39C/0x6D3E8)
art::OatFileManager::OpenDexFilesFromOat(hook后:0x6A2C0/0x6AF14/0x6B9B0/0x6C188/0x6CB5C)
0x6D4A0
0x6DAD8
0x6E40C
0x70410
art::DexFileVerifier::Verify(hook后:0x6EB04/0x6EB0C/0x6EB14,直接返回1)
art::DexFile::OpenMemory(hook后:0x74EE8/0x74E90/0x74F38)
Art::DexFile(hook后:0x74E30/0x74F88)
0x75054
0x75AA8
0x767F8
0x76C8C
0x76CCC
0x76D90
0x76DD4
0x76E18
0x7783C
0x79270
0x7A240
nuwa
andfix
hotfix
.RiskStu
tinker
0x80458
0x804A8
msync(hook后:0x78470)
close(hook后:0x7AF50)
munmap(hook后:0x7A568)
openat64(hook后:0x7DC48)
__open_2(hook后:0x7DC80)
_open64(hook后:0x7DCB8)
_openat_2(hook后:0x7DCF0)
ftruncate64(hook后:0x7DD30)
mmap64(hook后:0x7EF60)
pread64(hook后:0x7F5D0)
read(hook后:0x7F7DC)
write(hook后:0x8022C)
0x87F98
0x889B0
0x8A794/0x8B71C/0x8B890
0x917E8
0x91848
0x918A8
0x95778
0x95A28
0x95B9C
0x95D60
0x96398
0x995D0
.xposed.
xposedbridge
xposed_art
0x99D28
frida
ddi_hook
dexposed
substrate
adbi_hook
MSFindSymbol
hook_precall
hook_postcall
MSHookFunction
DexposedBridge
MSCloseFunction
dexstuff_loaddex
dexposedIsHooked
ALLINONEs_arthook
dexstuff_resolv_dvm
dexposedCallHandler
art_java_method_hook
artQuickToDispatcher
dexstuff_defineclass
dalvik_java_method_hook
art_quick_call_entrypoint
frida_agent_main
0x9CFCC
0x9D878
0x9DCF4
0x9ED44
0x9F770
0x9FD88
fart(https://github.com/hanbinglengyue/FART)
FUPK3(https://github.com/F8LEFT/FUPK3)
Youpk(https://github.com/Youlor/Youpk)
dumpMethodCode
fartthread
fart
android/app/fupk3/Fupk
android/app/fupk3/Global
android/app/fupk3/UpkConfig
android/app/fupk3/FRefInvoke
cn/youlor/Unpacker
0xA18D4
0xA7D3C
0xB4B94
write(hook后:0xAA2CC)
pwrite64(hook后:0xAA51C)
close(hook后:0xAA774)
read64(hook后:0xAAA9C)
openat64(hook后:0xAACB8)
__openat_2(hook后:0xAB6D4)
__open_2(hook后:0xAC0F4)
open64(hook后:0xACB10)
read(hook后:0xAFE18)
mmap64(hook后:0xB1C54)
这些hook是为了透明加密,具体没仔细看,之前论坛也有人分析过,估计应该没有太大的变化:梆梆加固之透明加密分析。
0xB9BEC
0xBAE64
0xC3378
0xC5DDC
0xC7B18
0xD024C
0xD1C04
0xD2E98
0xD6484
0xD5CDC
0xD6578
0xD68A8
0xD75A0
0x3EA68
1.初始化cpuabi字符串(arm64)于0x12E7C8
2.初始化so名字符串(libDexHelper)于0x12EC38
3.初始化字符串com/secneo/apkwrapper/H于0x137B10
4.调用0x1E520
5.
JNIEnv->FindClass(com/secneo/apkwrapper/H)
JNIEnv->GetStaticFieldID(com/secneo/apkwrapper/H.PKGNAMELjava/lang/String;)
JNIEnv->GetStaticObjectField(class com/secneo/apkwrapper/H, PKGNAME Ljava/lang/String; => "cn.missfresh.application")
JNIEnv->GetStringUtfChars("cn.missfresh.application")
7.
JNIEnv->FindClass(android/app/ActivityThread)
JNIEnv->GetStaticMethodID(android/app/ActivityThread.currentActivityThread()Landroid/app/ActivityThread;)
JNIEnv->CallStaticObjectMethodV(class android/app/ActivityThread, currentActivityThread())
JNIEnv->GetMethodID(android/app/ActivityThread.getSystemContext()Landroid/app/ContextImpl;)
JNIEnv->CallObjectMethodV(android.app.ActivityThread, getSystemContext())
JNIEnv->FindClass(android/app/ContextImpl)
JNIEnv->GetMethodID(android/app/ContextImpl.getPackageManager()Landroid/content/pm/PackageManager;)
JNIEnv->CallObjectMethodV(android.app.ContextImpl, getPackageManager())
JNIEnv->GetMethodID(android/content/pm/PackageManager.getPackageInfo(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;)
JNIEnv->NewStringUTF("cn.missfresh.application")
JNIEnv->CallObjectMethodV(android.content.pm.PackageManager, getPackageInfo("cn.missfresh.application", 0x0))
JNIEnv->GetFieldID(android/content/pm/PackageInfo.applicationInfo Landroid/content/pm/ApplicationInfo;)
JNIEnv->GetObjectField(android.content.pm.PackageInfo, applicationInfo Landroid/content/pm/ApplicationInfo;)
JNIEnv->GetFieldID(android/content/pm/ApplicationInfo.sourceDir Ljava/lang/String;)
JNIEnv->GetObjectField(android.content.pm.ApplicationInfo, sourceDir Ljava/lang/String; => "/data/app/cn.missfresh.application-1")
JNIEnv->GetStringUtfChars("/data/app/cn.missfresh.application-1")
JNIEnv->GetFieldID(android/content/pm/ApplicationInfo.dataDir Ljava/lang/String;)
JNIEnv->GetObjectField(android.content.pm.ApplicationInfo, dataDir Ljava/lang/String; => "/data/data/cn.missfresh.application")
JNIEnv->GetStringUtfChars("/data/data/cn.missfresh.application")
JNIEnv->GetFieldID(android/content/pm/ApplicationInfo.nativeLibraryDir Ljava/lang/String;)
JNIEnv->GetObjectField(android.content.pm.ApplicationInfo@36d64342, nativeLibraryDir Ljava/lang/String; => "/data/app/cn.missfresh.application-1/lib/arm64")
JNIEnv->GetStringUtfChars("/data/app/cn.missfresh.application-1/lib/arm64")
11.
JNIEnv->FindClass(com/secneo/apkwrapper/H)
JNIEnv->GetStaticFieldID(com/secneo/apkwrapper/H.ISMPAASLjava/lang/String;)
JNIEnv->GetStaticObjectField(class com/secneo/apkwrapper/H, ISMPAAS Ljava/lang/String; => "###MPAAS###")
JNIEnv->GetStringUtfChars("###MPAAS###")
13.调用0x22068
14.调用0x23568
15.调用0x1F250
16.将字符串lib/libart.so存放于0x1378A8
17.读/proc/self/maps,找权限为"r-xp"的lib/libart.so
18.初始化下列字符串:
/data/user/0/cn.missfresh.application/.cache
/data/user/0/cn.missfresh.application/.cache/oat/arm64
/data/user/0/cn.missfresh.application/.cache/classes.dve
/data/app/cn.missfresh.application-xxx/oat/arm64/base.odex
20.计算md5(不太清楚具体算的什么),0x12EC98指向0x130080,0x130080存放计算结果
21.access /data/user/0/cn.missfresh.application/.cache/classes.dve,不存在则把之前算的md5写入该文件;存在则读取其中的值和之前算的比较,不相等则写入新计算的值
22.调用0x3371C(根据标记位决定是否调用)
23.调用0x1FDC8
24.初始化下列字符串:
/data/user/0/cn.missfresh.application/.cache/libDexHelper32
/lib/armeabi-v7a/libDexHelper.so
/lib/armeabi/libDexHelper.so
assets/libDexHelper32
26.调用0xB4B94
27.调用0x9C0BC
28.调用0xD5CDC
29.调用0x24C08
30.调用0x1C40C
31.调用0xA7D3C
32.结束
参考
https://bbs.pediy.com/thread-252828.htm
总结
看雪ID:houjingyi
https://bbs.pediy.com/user-home-734571.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!